package zgame.main;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import zgame.bean.Port;
import zgame.bean.Service;
import zgame.socket.ServerConnection;
import zgame.socket.handle.GameServiceHandle;
import zgame.utils.Control;

public class ServiceController extends Control {
  public static final String SERVICE_CONTROL_PORT_NAME = "ServiceControl";
  
  private static Logger log = Logger.getLogger(ServiceController.class);
  private Map<String, Service> servicesById = new HashMap<String, Service>();
  private Map<Service.FUNCTION, List<Service>> serviceByFunction = new HashMap<Service.FUNCTION, List<Service>>();
  
  private static boolean isRunning = true;

  @Override
  public void perform() {
    ServerSocket servSock = null;
    try {
      Port serviceControlPort = Global.currentServiceInfo.getPort(SERVICE_CONTROL_PORT_NAME);
      servSock = new ServerSocket(serviceControlPort.getValue());
      log.info("-------------------------------------------------------");
      log.info("SERVICE CONTROLLER WAS STARTED AT PORT " + serviceControlPort.getValue());
      log.info("-------------------------------------------------------");
    } catch (IOException e1) {
      log.error("Service Controller can't start", e1);
      isRunning = false;
      return;
    }

    // Listening
    while (isRunning) {
      try {
        Socket clientSock = servSock.accept();
        log.info("ServiceController : new GameService accept: " + clientSock.getInetAddress().getHostAddress() + ":" + clientSock.getPort());
        new GameServiceHandle(new ServerConnection(clientSock), this);
      } catch (IOException e) {
        log.warn("Service Controller accept client fail", e);
      }
    }
  }
  
  public void storeService(Service service) {
    servicesById.put(service.getId(), service);
    if (service.getFunction() != null) {
      getServicesByFunction(service.getFunction()).add(service);
    }
  }
  
  public Service getServiceById(String serviceId) {
    return servicesById.get(serviceId);
  }
  
  public List<Service> getServicesByFunction(Service.FUNCTION function) {
    List<Service> serviceByFunctionList = serviceByFunction.get(function);
    if (serviceByFunctionList == null) {
      serviceByFunctionList = new ArrayList<Service>();
      serviceByFunction.put(function, serviceByFunctionList);
    }
    return serviceByFunctionList;
  }
  
  public void removeService(String serviceId) {
    Service service = servicesById.remove(serviceId);
    if ((service != null) && (service.getFunction() != null)) {
      getServicesByFunction(service.getFunction()).remove(service);
    }
  }
  
  public boolean isRunning() {
    return isRunning;
  }

  public void stopGameService() {
    isRunning = false;
  }
}
